package com.wu.ssm.spring.utils;

import com.wu.ssm.spring.utils.StringUtil;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * Class.forName()方法
 * 此方法含义是：加载参数指定的类，并且初始化它。
 * 在jdbc连接数据库中的应用
 * 到这里，不用解释，读者也会明白，在使用jdbc方式连接数据库时，为什么要执行Class.forName('驱动类名')方法了：将驱动类的class文件装载到内存中，并且形成一个描述此驱动类结构的Class类实例，并且初始化此驱动类，这样jvm就可以使用它了，这就是Class.forName()方法的含义。
 *
 * 有数据库开发经验朋友会发现，为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢？即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一 些：Class.forName(xxx.xx.xx).newInstance()，为什么会有这两种写法呢？
 * 刚才提到，Class.forName("");的作用是要求JVM查找并加载指定的类，如果在类中有静态初始化器的话，JVM必然会执行该类的静态代码 段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己，即任何一个JDBC Driver的 Driver类的代码都必须类似如下：
 *   public class MyJDBCDriver implements Driver {
 *   static {
 *      DriverManager.registerDriver(new MyJDBCDriver());
 *     }
 *   }
 * 既然在静态初始化器的中已经进行了注册，所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。
 * Created by wzf on 2018/11/26/026.
 */
public class ClassUtil {


    public static ClassLoader getClassLoader(){
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 加载类（按参数是否初始化）
     */
    public static Class<?> loadClass(String className, boolean isInittialized){
        Class<?> cls;

        try {
            cls = Class.forName(className, isInittialized, getClassLoader());
        } catch (ClassNotFoundException e) {
           throw new RuntimeException();
        }
        return cls;
    }


    /**
     * 加载类（默认将初始化类）
     */
    public static Class<?> loadClass(String className) {
        return loadClass(className, true);
    }

    /**
     * 加载指定包下的所有类
     * @param @param  packageName
     * @param @return 设定文件
     * @return Set<Class<?>>    返回类型
     */
    public static Set<Class<?>> getClassSet(String packageName){

        Set<Class<?>> classSet = new HashSet<>();

        URL url = getClassLoader().getResource("" + replaysPath(packageName));
        String pathFile = url.getFile();
        String protocol = url.getProtocol();
        // 返回URL的协议
        if (protocol.equals("file")) {
            addClass(classSet, pathFile, packageName);
        }

        return classSet;
    }



    private static void doAddClass(Set<Class<?>> classSet, String className) {
        Class<?> cls = loadClass(className, false);
        classSet.add(cls);
    }
    /**
     * 添加文件到SET集合
     *
     * @param @param classSet
     * @param @param packagePath  /类型的路径
     * @param @param packageName  .类型的路径
     * @return void    返回类型
     * @throws
     * @Title: addClass
     * @Description:
     */
    private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {

        File[] files = new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
            }
        });

        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));

                if (StringUtil.isNotEmpty(packageName)) {
                    className = packageName + "." + className;
                }
                // 添加
                doAddClass(classSet, className);
            } else {
                // 子目录
                String subPackagePath = fileName;
                if (StringUtil.isNotEmpty(packagePath)) {
                    subPackagePath = packagePath + "/" + subPackagePath;
                }

                String subPackageName = fileName;
                if (StringUtil.isNotEmpty(packageName)) {
                    subPackageName = packageName + "." + subPackageName;
                }

                addClass(classSet, subPackagePath, subPackageName);
            }
        }

    }

    /**
     * 是否为 int 类型（包括 Integer 类型）
     */
    public static boolean isInt(Class<?> type) {
        return type.equals(int.class) || type.equals(Integer.class);
    }

    /**
     * 是否为 long 类型（包括 Long 类型）
     */
    public static boolean isLong(Class<?> type) {
        return type.equals(long.class) || type.equals(Long.class);
    }

    /**
     * 是否为 double 类型（包括 Double 类型）
     */
    public static boolean isDouble(Class<?> type) {
        return type.equals(double.class) || type.equals(Double.class);
    }

    /**
     * 是否为 String 类型
     */
    public static boolean isString(Class<?> type) {
        return type.equals(String.class);
    }


    /**
     * 包名和路径转义
     */
    private static String replaysPath(String packageName) {
        return packageName.replaceAll("\\.","/");
    }

    public static void main(String[] args) {
        File[] files = new File("D:\\workspace\\ssm\\target\\classes\\com\\wu\\ssm").listFiles();

        System.out.println(files);
    }
}
